using LuaInterface;
using System;
using System.Collections.Generic;
using System.Text;
using virtuaPol.Model;
using virtuaPol.Util;

namespace virtuaPol.WorldEditor
{
    class EventScriptTester
    {
        private CWorld m_world;
        private string m_eventScript;

        private delegate bool DoSimulation();
        private delegate void DoEvent();
        private delegate bool InitTest();
        private delegate bool CheckTestResult();

        public EventScriptTester(CWorld w, string scr)
        {
            m_world = w;
            m_eventScript = scr;
        }
     
        public bool Test()
        {
            object[] res;
            Lua lua = new Lua();
            try
            {
                lua.DebugHook += new EventHandler<DebugHookEventArgs>(lua_DebugHook);
                lua.HookException += new EventHandler<HookExceptionEventArgs>(lua_HookException);
                lua.DoString(m_eventScript, "testScript");
                lua["world"] = m_world;
                // Initialize test case
                LuaFunction initTest = lua.GetFunction("initTest");
                if (initTest == null)
                {
                    System.Windows.Forms.MessageBox.Show(
                        "Function initTest not found!", "Error",
                        System.Windows.Forms.MessageBoxButtons.OK,
                        System.Windows.Forms.MessageBoxIcon.Error);
                    return false;
                }
                res = initTest.Call(new object[] { });
                if (res.Length < 1)
                {
                    testFailedMsg("initTest() didn't return a value.");
                }
                bool shouldSucceed = (bool)res[0];
                // Do test simulation
                LuaFunction doSimulation = lua.GetFunction("doSimulation");
                if (doSimulation == null)
                {
                    System.Windows.Forms.MessageBox.Show(
                        "Function doSimulation not found!", "Error",
                        System.Windows.Forms.MessageBoxButtons.OK,
                        System.Windows.Forms.MessageBoxIcon.Error);
                    return false;
                }
                res = doSimulation.Call(new object[] { });
                if (res.Length < 1)
                {
                    testFailedMsg("doSimulation() didn't return a value.");
                }
                bool simulationResult = (bool)res[0];
                if (shouldSucceed != simulationResult)
                {
                    testFailedMsg(String.Format("The test failed: the simulation should have {0}, but it didn't.",
                        (shouldSucceed ? "succeeded" : "failed")));
                    return false;
                }

                if (simulationResult)
                {
                    // Trigger event
                    LuaFunction doEvent = lua.GetFunction("doEvent");
                    if (doEvent == null)
                    {
                        System.Windows.Forms.MessageBox.Show(
                            "Function doEvent not found!", "Error",
                            System.Windows.Forms.MessageBoxButtons.OK,
                            System.Windows.Forms.MessageBoxIcon.Error);
                        return false;
                    }
                    doEvent.Call(new object[] { });
                    // Check test result
                    LuaFunction checkTestResult = lua.GetFunction("checkTestResult");
                    if (checkTestResult == null)
                    {
                        System.Windows.Forms.MessageBox.Show(
                            "Function checkTestResult not found!", "Error",
                            System.Windows.Forms.MessageBoxButtons.OK,
                            System.Windows.Forms.MessageBoxIcon.Error);
                        return false;
                    }
                    res = checkTestResult.Call(new object[] { });
                    if (res.Length < 1)
                    {
                        testFailedMsg("checkTestResult() didn't return a value.");
                    }
                    bool checkResult = (bool)res[0];
                    if (!checkResult)
                    {
                        testFailedMsg("The test failed: the event was triggered but the world object wasn't modified as expected.");
                        return false;
                    }
                }

                return true;
            }
            catch (Exception ex)
            {
                CLogger.LogError(ex);
                System.Windows.Forms.MessageBox.Show(
                String.Format("[{0}] {1} (in {2}:{3}:{4})\n{5}",
                    ex.GetType().FullName,
                    ex.Message,
                    ex.Source,
                    ex.TargetSite.ReflectedType.FullName,
                    ex.TargetSite.Name,
                    ex.StackTrace
                ),
                "Lua Exception",
                System.Windows.Forms.MessageBoxButtons.OK,
                System.Windows.Forms.MessageBoxIcon.Error);
                return false;
            }
        }

        void lua_HookException(object sender, HookExceptionEventArgs e)
        {
            Exception ex = e.Exception;
            CLogger.LogError(ex);
            System.Windows.Forms.MessageBox.Show(
                String.Format("[{0}] {1} (in {2}:{3}:{4})\n{5}", 
                    ex.GetType().FullName,
                    ex.Message,
                    ex.Source,
                    ex.TargetSite.ReflectedType.FullName,
                    ex.TargetSite.Name,
                    ex.StackTrace
                ),
                "Lua Exception",
                System.Windows.Forms.MessageBoxButtons.OK,
                System.Windows.Forms.MessageBoxIcon.Error);
        }

        void lua_DebugHook(object sender, DebugHookEventArgs e)
        {
            LuaDebug d = e.LuaDebug;
            System.Windows.Forms.MessageBox.Show(
                String.Format("[{0}] {1} (in {2} at line {3}",
                    d.namewhat, d.what, d.name, d.currentline),
                "Lua Debug",
                 System.Windows.Forms.MessageBoxButtons.OK,
                  System.Windows.Forms.MessageBoxIcon.Information);
        }

        private void testFailedMsg(string msg)
        {
            System.Windows.Forms.MessageBox.Show(
                msg,
                "Test failed!",
                System.Windows.Forms.MessageBoxButtons.OK,
                System.Windows.Forms.MessageBoxIcon.Exclamation);
        }
    }
}
